package com.qingcheng.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.qingcheng.dao.BrandMapper;
import com.qingcheng.dao.SpecMapper;
import com.qingcheng.pojo.goods.Brand;
import com.qingcheng.service.goods.SkuSearchService;
import com.qingcheng.util.CacheEnum;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class SkuSearchServiceImpl implements SkuSearchService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private BrandMapper brandMapper;

    @Autowired
    private SpecMapper specMapper;

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 定义根据条件集合查询所有商品sku的方法
     * @param searchMap
     * @return
     */
    @Override
    public Map findSkuBySearchMap(Map<String, String> searchMap) {
        //1. 指定数据库库名和数据存储格式type
        SearchRequest searchRequest=new SearchRequest("sku");
        searchRequest.types("doc");

        //2. 定义条件查询构建器 query
        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
        //定义bool查询构建器 bool
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//布尔查询构建器

        //定义match查询构造器match
        //定义按照名字分词查询数据
        MatchQueryBuilder matchQueryBuilder= QueryBuilders.matchQuery("name",searchMap.get("name"));
        //将match装入bool
        boolQueryBuilder.must(matchQueryBuilder);

        //定义分组查询出商品的分类
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("category").field("categoryName");
        searchSourceBuilder.aggregation(termsAggregationBuilder);

        //定义过滤查询，根据categoryName精准查询
        if(searchMap.get("category")!=null && !"".equals(searchMap.get("category")) ){
            //精准查询
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("categoryName", searchMap.get("category"));
            boolQueryBuilder.filter(termQueryBuilder);
        }

        //定义过滤查询，根据brandName精准查询
        if(searchMap.get("brand")!=null && !"".equals(searchMap.get("brand"))){
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", searchMap.get("brand"));
            boolQueryBuilder.filter(termQueryBuilder);
        }
        //定义过滤查询，根据spec.颜色='红色'，精准查询
        //遍历searchMap集合，查询出所有以spe.开头的键值
        for(String key:searchMap.keySet()){
            if(key.startsWith("spec.")){ //如果以spec.开头
                //定义过滤查询
                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(key+".keyword", searchMap.get(key));
                boolQueryBuilder.filter(termQueryBuilder);
            }
        }

        //定义bool查询的must条件查询
        //判断前端传入的参数price是否为空
        if(searchMap.get("price")!=null && !"".equals(searchMap.get("price"))){
            String[] prices = searchMap.get("price").split("-");
            //判断第一个参数是否为0
            if(!"0".equals(prices[0])){
                //当下限不为0，用0索引作为下限查询
                //数据库price单位为分，所以要加00
                RangeQueryBuilder rangeQueryBuilder=QueryBuilders.rangeQuery("price").gte(prices[0]+"00");
                boolQueryBuilder.must(rangeQueryBuilder);
            }
            if(!"*".equals(prices[1])){
                RangeQueryBuilder rangeQueryBuilder=QueryBuilders.rangeQuery("price").lte(prices[1]+"00");
                boolQueryBuilder.must(rangeQueryBuilder);
            }
        }

        //定义分页条件查询
        //将前台传入的页数转为数字格式
        int pageNo = Integer.parseInt(searchMap.get("pageNo"));
        //计算起始索引
        searchSourceBuilder.from((pageNo-1)*30);
        searchSourceBuilder.size(30);

        //定义根据条件排序查询
        if(searchMap.get("sortName")!=null && !"".equals(searchMap.get("sortName"))){
            //如果sortName为空,默认综合排序
            if(searchMap.get("sortOrder")!=null && !"".equals(searchMap.get("sortOrder"))){
                //根据字段，按照自定义的排序方式排序
                searchSourceBuilder.sort(searchMap.get("sortName"), SortOrder.valueOf(searchMap.get("sortOrder")));
            }else{
                //根据字段，按照默认排序方式
                searchSourceBuilder.sort(searchMap.get("sortName"),SortOrder.valueOf("DESC"));
            }
        }
        //定义高亮查询方法
        HighlightBuilder highlightBuilder=new HighlightBuilder();
        highlightBuilder.field("name").preTags("<font style='color:red'>").postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);


        //将bool装入source（query）
        searchSourceBuilder.query(boolQueryBuilder);

        //3. 将query装入request
        searchRequest.source(searchSourceBuilder);


        //4. 处理响应
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SearchHits searchHits = searchResponse.getHits();
        int totalHits =(int) searchHits.getTotalHits();
        System.out.println("记录数："+totalHits);
        //计算总页数
        int totalPages=(totalHits%30)==0?(totalHits/30):(totalHits/30+1);
        System.out.println(totalPages);
        //处理商品name查询，创建List集合封装sku数据
        List<Map> skuList=new ArrayList<Map>();
        SearchHit[] hits = searchHits.getHits();
        for(SearchHit hit:hits){
            //获取结果中的高亮数据
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField highlightField = highlightFields.get("name");
            //高亮数据是数组，默认是0索引位置的数据
            Text[] names = highlightField.fragments();
            String name = names[0].toString();


            //FastJSON将每条数据转换为map集合
            Map<String, Object> skuMap = hit.getSourceAsMap();
            //将sku装入list
            skuMap.put("name",name);
            skuList.add(skuMap);
        }

        //处理商品分类的响应信息
        Aggregations aggregations = searchResponse.getAggregations();
        Map<String, Aggregation> asMap = aggregations.getAsMap();
        Terms terms = (Terms) asMap.get("category");
        List<? extends Terms.Bucket> buckets = terms.getBuckets();
        //创建list集合封装category
        List<String> categoryList=new ArrayList<String>();
        for(Terms.Bucket bucket:buckets){
            String category = bucket.getKeyAsString();
            categoryList.add(category);
        }
        //获取第一个category作为品牌的搜索条件
        List<Map> brandList=new ArrayList<Map>();
        //获取第一个category作为规格的搜索条件
        List<Map> specList=new ArrayList<Map>();
        if(searchMap.get("category")==null){
            //第一次搜索，根据name，此时默认使用第一个商品分类作为品牌查询条件
            if(categoryList.size()!=0){
                String categoryName = categoryList.get(0);
                //从缓存redis中获取brandList和specList
                 brandList = (List<Map>) redisTemplate.boundHashOps(CacheEnum.BrandList).get(categoryName);
                 if(brandList==null){
                     //如果缓存库不存在，从数据库中查询，并放入缓存库
                     brandList = brandMapper.findBrandByTemplate(categoryName);
                     redisTemplate.boundHashOps(CacheEnum.BrandList).put(categoryName,brandList);
                     //设置过期时间为随机数
                     Random random=new Random();
                     int minute=random.nextInt(300);
                     redisTemplate.expire(CacheEnum.BrandList,minute, TimeUnit.MINUTES);
                 }
                 specList = (List<Map>) redisTemplate.boundHashOps(CacheEnum.SpecList).get(categoryName);
                if(specList==null){
                    //如果缓存库不存在，从数据库中查询，并放入缓存库
                    specList= specMapper.findSpecByTemplate(categoryName);
                    redisTemplate.boundHashOps(CacheEnum.SpecList).put(categoryName,specList);
                    //设置过期时间为随机数
                    Random random=new Random();
                    int minute=random.nextInt(300);
                    redisTemplate.expire(CacheEnum.SpecList,minute, TimeUnit.MINUTES);
                }

               /*
                specList= specMapper.findSpecByTemplate(categoryName);*/
            }

        }else{
            //在缓存中获取数据
            brandList = (List<Map>) redisTemplate.boundHashOps(CacheEnum.BrandList).get(searchMap.get("category"));
            if(brandList==null){
                //如果缓存库不存在，从数据库中查询，并放入缓存库
                brandList = brandMapper.findBrandByTemplate(searchMap.get("category"));
                redisTemplate.boundHashOps(CacheEnum.BrandList).put(searchMap.get("category"),brandList);
                //设置过期时间为随机数
                Random random=new Random();
                int minute=random.nextInt(300);
                redisTemplate.expire(CacheEnum.BrandList,minute, TimeUnit.MINUTES);
            }
            specList = (List<Map>) redisTemplate.boundHashOps(CacheEnum.SpecList).get(searchMap.get("category"));
            if(specList==null){
                //如果缓存库不存在，从数据库中查询，并放入缓存库
                specList= specMapper.findSpecByTemplate(searchMap.get("category"));
                redisTemplate.boundHashOps(CacheEnum.SpecList).put(searchMap.get("category"),specList);
                //设置过期时间为随机数
                Random random=new Random();
                int minute=random.nextInt(300);
                redisTemplate.expire(CacheEnum.SpecList,minute, TimeUnit.MINUTES);
            }

          /*   brandList = brandMapper.findBrandByTemplate(searchMap.get("category"));

             specList= specMapper.findSpecByTemplate(searchMap.get("category"));*/
        }

        //处理specList中的options,字符串变数组
        if(specList.size()!=0){
            for (Map specMap : specList) {
                //options =300万像素,800万像素
                String options = (String) specMap.get("options");
                specMap.put("options",options.split(","));
            }
        }


        //5 .创建map集合封装数据返回到浏览器
        Map resultMap=new HashMap();
        resultMap.put("skuList",skuList); //封装商品sku信息
        resultMap.put("categoryList",categoryList); //封装商品分类
        resultMap.put("brandList",brandList); //封装品牌信息
        resultMap.put("specList",specList);  //封装规格信息
        resultMap.put("totalPages",totalPages);
        return resultMap;
    }
}
